package com.itheima.nio.buffer.demo10;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 演示NIO网络模型中的Selector选择器的使用
 */
public class NioServerSelectorDemo01 {

    public static void main(String[] args) throws IOException {

        /**
         * 步骤：
         * 1. 打开ServerSocketChannel
         * 2. 进行端口号绑定
         * 3. 设置ServerSocketChannel为非阻塞
         * 4. 开启一个选择器
         * 5. 将ServerSocketChannel通道注册到选择器上
         * 6. 循环调用选择器来进行选择操作
         * 7. 获取所有的有就绪任务的通道信息
         * 8. 遍历，然后进行判断，根据任务的类型给出相关的处理方案
         */

        // 1. 打开ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 2. 进行端口号绑定
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));

        // 3. 设置ServerSocketChannel为非阻塞
        serverSocketChannel.configureBlocking(false) ;

        // 4. 开启一个选择器
        Selector selector = Selector.open();

        // 5. 将ServerSocketChannel通道注册到选择器上
        // 第二个参数，表示的意义就是这个通道可以做的事情(任务类型) , 这个任务类型可以只用SelectionKey中的静态成员来指定
        serverSocketChannel.register(selector , SelectionKey.OP_ACCEPT) ;

        // 循环
        while(true) {

            // 进行选择操作
            int select = selector.select();     // 这个方法是一个阻塞方法 ， 方法的返回值就是具有就绪任务的通道的个数

            if (select != 0) {

                // 获取所有的有就绪任务的通道信息
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();

                // 遍历集合，获取每一个就有就绪任务的通道然后进行处理
                while (iterator.hasNext()) {

                    SelectionKey selectionKey = iterator.next();        // SelectionKey封装的就是通道的信息
                    if(selectionKey.isAcceptable()) {                   // 接收连接的任务已经就绪了

                        ServerSocketChannel serverSocketChannel1 = (ServerSocketChannel)selectionKey.channel() ;
                        SocketChannel socketChannel = serverSocketChannel1.accept();        // 接收连接
                        socketChannel.configureBlocking(false) ;
                        socketChannel.register(selector , SelectionKey.OP_READ) ;           // 把通道注册到选择器上

                    }else if(selectionKey.isReadable()) {               // 可以读取数据了

                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        SocketChannel socketChannel = (SocketChannel)selectionKey.channel() ;
                        int read = socketChannel.read(byteBuffer);
                        while(read > 0) {
                            byteBuffer.flip() ;
                            System.out.println(new String(byteBuffer.array() , 0 , read));
                            byteBuffer.clear() ;
                            read = socketChannel.read(byteBuffer);
                        }

                        // 给出客户端的响应
                        ByteBuffer buffer = ByteBuffer.wrap("OK,收到了".getBytes("UTF-8"));
                        socketChannel.write(buffer) ;

                        // 关闭通道
                        socketChannel.close();

                    }

                    // 操作完毕以后需要把这个通道从已选择的selectionKeys中移除掉，否则下一次操作，还会对这个通道进行操作
//                    iterator.remove();

                }

            }

        }
    }

}



















